package com.yyy.tcc.service.compensation;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 演示Integer的并发问题和AtomicInteger的解决方案
 */
public class AtomicIntegerDemo {
    private static final Logger log = LoggerFactory.getLogger(AtomicIntegerDemo.class);

    // 普通Integer计数器
    private Integer unsafeCounter = 0;
    // 使用synchronized的Integer计数器
    private Integer syncCounter = 0;
    // AtomicInteger计数器
    private AtomicInteger atomicCounter = new AtomicInteger(0);

    /**
     * 测试三种不同的计数器在并发情况下的表现
     */
    @Test
    public void testCounter() throws InterruptedException {
        int threadCount = 100;  // 线程数
        int incrementsPerThread = 1000;  // 每个线程增加的次数
        int expectedTotal = threadCount * incrementsPerThread;  // 期望的最终结果

        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        CountDownLatch latch = new CountDownLatch(threadCount * 3);  // 3个测试都用同一个latch

        // 1. 测试不安全的计数器
        long startUnsafe = System.currentTimeMillis();
        for (int i = 0; i < threadCount; i++) {
            executorService.submit(() -> {
                try {
                    for (int j = 0; j < incrementsPerThread; j++) {
                        unsafeIncrement();
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        // 2. 测试同步的计数器
        for (int i = 0; i < threadCount; i++) {
            executorService.submit(() -> {
                try {
                    for (int j = 0; j < incrementsPerThread; j++) {
                        synchronizedIncrement();
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        // 3. 测试AtomicInteger
        for (int i = 0; i < threadCount; i++) {
            executorService.submit(() -> {
                try {
                    for (int j = 0; j < incrementsPerThread; j++) {
                        atomicIncrement();
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        // 等待所有线程完成
        latch.await();
        long endTime = System.currentTimeMillis();

        // 输出结果
        log.info("\n========== 并发计数器测试结果 ==========");
        log.info("期望结果: {}", expectedTotal);
        log.info("不安全计数器(Integer)结果: {} (错误的结果)", unsafeCounter);
        log.info("同步计数器(synchronized)结果: {} (正确但性能较差)", syncCounter);
        log.info("原子计数器(AtomicInteger)结果: {} (正确且性能好)", atomicCounter.get());
        log.info("总耗时: {}ms", endTime - startUnsafe);
        log.info("=====================================\n");

        executorService.shutdown();
    }

    /**
     * 不安全的自增操作 - 会出现并发问题
     */
    private void unsafeIncrement() {
        unsafeCounter++;  // 非原子操作，会出现并发问题
    }

    /**
     * 使用synchronized的自增操作 - 线程安全但性能较差
     */
    private synchronized void synchronizedIncrement() {
        syncCounter++;  // 使用synchronized保证线程安全
    }

    /**
     * 使用AtomicInteger的自增操作 - 线程安全且性能好
     */
    private void atomicIncrement() {
        atomicCounter.incrementAndGet();  // 原子操作，线程安全
    }

    /**
     * 演示AtomicInteger的CAS操作
     */
    @Test
    public void testAtomicCAS() {
        AtomicInteger atomic = new AtomicInteger(100);

        // 演示CAS操作
        boolean success1 = atomic.compareAndSet(100, 200);  // 期望值是100，设置新值200
        log.info("第一次CAS结果: {} (应该成功), 当前值: {}", success1, atomic.get());

        boolean success2 = atomic.compareAndSet(100, 300);  // 期望值是100，但实际已经是200了
        log.info("第二次CAS结果: {} (应该失败), 当前值: {}", success2, atomic.get());

        // 演示原子更新
        int newValue = atomic.updateAndGet(x -> x * 2);  // 原子性地将值翻倍
        log.info("原子更新结果: {} (应该是400)", newValue);

        // 演示原子累加
        int result = atomic.accumulateAndGet(50, Integer::sum);  // 原子性地加50
        log.info("原子累加结果: {} (应该是450)", result);
    }
}
